﻿namespace HutongGames.PlayMakerEditor
{
    using HutongGames.PlayMaker;
    using System;
    using UnityEditor;
    using UnityEngine;

    [Serializable]
    internal class FsmDebugger
    {
        public static readonly FsmDebugger Instance = new FsmDebugger();
        [SerializeField]
        private FsmStepMode stepMode;

        private FsmDebugger()
        {
            Application.RegisterLogCallback(new Application.LogCallback(this.HandleLog));
        }

        private static void DoBreak(Fsm fsm)
        {
            if (Fsm.IsErrorBreak)
            {
                FsmErrorChecker.AddRuntimeError(Fsm.LastError);
            }
            if (FsmEditorSettings.JumpToBreakpoint && (FsmEditor.Instance != null))
            {
                FsmEditor.GotoBreakpoint();
            }
            if (fsm != null)
            {
                fsm.HitBreakpoint = false;
            }
            EditorApplication.isPaused = true;
        }

        public static void EnableBreakpoints(bool enabled)
        {
            foreach (Fsm fsm in FsmEditor.FsmList)
            {
                if (fsm != null)
                {
                    fsm.BreakpointsEnabled = enabled;
                }
            }
        }

        public void HandleLog(string logEntry, string stackTrace, LogType type)
        {
            if (((type == LogType.Error) && (Fsm.ExecutingFsm != null)) && (((GameStateTracker.CurrentState != GameState.Stopped) && stackTrace.Contains("HutongGames.PlayMaker")) && !stackTrace.Contains("HutongGames.PlayMaker.Fsm:LogError(String)")))
            {
                Fsm.ExecutingFsm.DoBreakError(logEntry);
                DoBreak(Fsm.ExecutingFsm);
            }
        }

        public void ResetStep()
        {
            Fsm.StepToStateChange = false;
        }

        public static void SetInfiniteLoopThreshold(int threshold)
        {
            foreach (Fsm fsm in FsmEditor.FsmList)
            {
                if (fsm != null)
                {
                    fsm.MaxReEnterStateCount = threshold;
                }
            }
        }

        public void Step()
        {
            switch (this.StepMode)
            {
                case FsmStepMode.StepFrame:
                    DebugFlow.UpdateTime();
                    EditorApplication.isPaused = false;
                    EditorApplication.Step();
                    Fsm.StepToStateChange = false;
                    return;

                case FsmStepMode.StepToStateChange:
                    EditorApplication.isPaused = false;
                    Fsm.StepToStateChange = true;
                    Fsm.StepFsm = FsmEditor.SelectedFsm;
                    return;

                case FsmStepMode.StepToAnyStateChange:
                    EditorApplication.isPaused = false;
                    Fsm.StepToStateChange = true;
                    Fsm.StepFsm = null;
                    return;
            }
        }

        public void Update()
        {
            if (GameStateTracker.CurrentState != GameState.Stopped)
            {
                foreach (Fsm fsm in Fsm.FsmList)
                {
                    if (fsm != null)
                    {
                        this.Watch(fsm);
                    }
                }
            }
        }

        public void Watch(Fsm fsm)
        {
            fsm.BreakpointsEnabled = FsmEditorSettings.BreakpointsEnabled;
            if (fsm.SwitchedState)
            {
                if ((FsmEditorSettings.SelectStateOnActivated && (FsmEditor.Instance != null)) && (FsmEditor.SelectedFsm == fsm))
                {
                    FsmEditor.SelectState(fsm.ActiveState, false);
                }
                fsm.SwitchedState = false;
            }
            if (fsm.HitBreakpoint)
            {
                DoBreak(fsm);
            }
        }

        public FsmStepMode StepMode
        {
            get
            {
                return this.stepMode;
            }
            set
            {
                this.stepMode = value;
            }
        }

        internal enum FsmStepMode
        {
            StepFrame,
            StepToStateChange,
            StepToAnyStateChange
        }
    }
}

